package com.yonyou.permission.util;

import com.yonyou.cloud.bean.RemoteCallInfo;
import com.yonyou.cloud.middleware.rpc.RPCStubBeanFactory;
import com.yonyou.cloud.middleware.rpc.RemoteCall;
import com.yonyou.diwork.service.auth.IDiWorkPermissionService;
import com.yonyou.diwork.service.auth.IServiceIsolateService;
import com.yonyou.iuap.auth.api.orgperm.IOrgPermManagerService;
import com.yonyou.permission.itf.IAuthPermissionService;
import com.yonyou.permission.itf.bill.IRoleConstraintResolver;
import com.yonyou.permission.services.SdkDynamicTokenManagerService;
import com.yonyou.uap.tenant.service.itf.ITenantRoleService;
import com.yonyou.uap.tenant.service.itf.ITenantRoleUserService;
import com.yonyou.uap.tenantauth.entity.TenantRole;
import com.yonyou.uap.tenantauth.entity.TenantRoleUser;
import com.yonyou.ucf.mdd.ext.consts.Constants;
import com.yonyou.ucf.mdd.ext.core.AppContext;
import com.yonyou.ucf.mdd.isv.service.ISVServiceFactory;
import com.yonyou.workbench.model.DiworkPermissionFilter;
import com.yonyou.workbench.model.OrgPermVO;
import com.yonyou.workbench.param.OrgEntryParam;
import com.yonyoucloud.uretail.sys.auth.DataPermissionRequestDto;
import com.yonyoucloud.uretail.sys.auth.DataPermissionResponseDto;
import com.yonyoucloud.uretail.sys.auth.OrgPermissionsParam;
import com.yonyoucloud.uretail.sys.pubItf.IDataPermissionService;
import com.yonyoucloud.uretail.sys.pubItf.IOrgPermissionService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:统一入口工具类。远程接口实例通过iris方式获取，需要工程接入iris
 * @Company: yonyou
 * @author: zhuyjh
 * @date: 2021/09/27
 */

@Component
public class AuthSdkFacadeUtils {
    private static Logger logger = LoggerFactory.getLogger(AuthSdkFacadeUtils.class);

    public static String SYSTEM_DIWORK = "diwork";

    public static final String AUTHDOMAIN = "diwork-auth";

    public static final String ORGDOMAIN = "iuap-apcom-auth";

    private static IAuthPermissionService authPermissionService;
    //组织权限
    private static IServiceIsolateService serviceIsolateService;
    //新版组织权限
    private static IOrgPermissionService orgPermissionService;
    //数据权限
    private static IDataPermissionService dataPermissionService;
    //功能权限
    private static IDiWorkPermissionService diWorkPermissionService;
    //角色
    private static ITenantRoleService tenantRoleService;
    //用户角色
    private static ITenantRoleUserService tenantRoleUserService;

    private static IRoleConstraintResolver roleConstraintResolver;

    private static SdkDynamicTokenManagerService sdkDynamicTokenManagerService;

    private static AuthSdkFacadeUtils instance = null;

    public static String accessKey = null;

    public static String accessSecret = null;

    private static IOrgPermManagerService orgPermManagerService;

    @Value("${access.key}")
    public void setAccessKey(String accessKey) {
        AuthSdkFacadeUtils.accessKey = accessKey;
    }

    @Value("${access.secret}")
    public void setAccessSecret(String accessSecret) {
        AuthSdkFacadeUtils.accessSecret = accessSecret;
    }

    @Autowired(required = false)
    public void setRoleConstraintResolver(IRoleConstraintResolver roleConstraintResolver) {
        AuthSdkFacadeUtils.roleConstraintResolver = roleConstraintResolver;
    }

    @Autowired(required = false)
    public void setSdkDynamicTokenManagerService(SdkDynamicTokenManagerService sdkDynamicTokenManagerService) {
        AuthSdkFacadeUtils.sdkDynamicTokenManagerService = sdkDynamicTokenManagerService;
    }

    @Autowired(required = false)
    public void setAuthPermissionService(IAuthPermissionService authPermissionService) {
        AuthSdkFacadeUtils.authPermissionService = authPermissionService;
    }

    @Autowired(required = false)
    public void setServiceIsolateService(IServiceIsolateService serviceIsolateService) {
        if (serviceIsolateService == null) {
            serviceIsolateService = getRemoteService(IServiceIsolateService.class, null);
        }
        AuthSdkFacadeUtils.serviceIsolateService = serviceIsolateService;
    }

    @Autowired(required = false)
    public void setOrgPermManagerService(IOrgPermManagerService orgPermManagerService) {
        if (orgPermManagerService == null) {
            orgPermManagerService = (IOrgPermManagerService)getRemoteService(IOrgPermManagerService.class, (RemoteCallInfo)null);
        }

        AuthSdkFacadeUtils.orgPermManagerService = orgPermManagerService;
    }

    @Autowired(required = false)
    public void setDataPermissionService(IDataPermissionService dataPermissionService) {
        if (dataPermissionService == null) {
            dataPermissionService = getRemoteService(IDataPermissionService.class, null);
        }
        AuthSdkFacadeUtils.dataPermissionService = dataPermissionService;
    }

    @Autowired(required = false)
    public void setDiWorkPermissionService(IDiWorkPermissionService diWorkPermissionService) {
        if (diWorkPermissionService == null) {
            diWorkPermissionService = getRemoteService(IDiWorkPermissionService.class, null);
        }
        AuthSdkFacadeUtils.diWorkPermissionService = diWorkPermissionService;
    }

    @Autowired(required = false)
    @Lazy
    public void setInstance(AuthSdkFacadeUtils instance) {
        AuthSdkFacadeUtils.instance = instance;
    }

    @Autowired(required = false)
    public void setTenantRoleService(ITenantRoleService tenantRoleService) {
        if (tenantRoleService == null) {
            tenantRoleService = getRemoteService(ITenantRoleService.class, null);
        }
        AuthSdkFacadeUtils.tenantRoleService = tenantRoleService;
    }

    @Autowired(required = false)
    public void setTenantRoleUserService(ITenantRoleUserService tenantRoleUserService) {
        if (tenantRoleUserService == null) {
            tenantRoleUserService = getRemoteService(ITenantRoleUserService.class, null);
        }
        AuthSdkFacadeUtils.tenantRoleUserService = tenantRoleUserService;
    }

    @Autowired(required = false)
    public void setOrgPermissionService(IOrgPermissionService orgPermissionService) {
        if (orgPermissionService == null) {
            orgPermissionService = getRemoteService(IOrgPermissionService.class, null);
        }
        AuthSdkFacadeUtils.orgPermissionService = orgPermissionService;
    }


    public static <T> T getRemoteService(Class<T> cls, RemoteCallInfo callInfo) {
        RemoteCall classRemoteCall = cls.getAnnotation(RemoteCall.class);
        String appCode = null;
        String nameSpace = null;
        String alias = null;

        if (classRemoteCall != null) {
            String valueStr = classRemoteCall.value();
            String[] valueArgs = valueStr.split("@");
            appCode = valueArgs[0];
            nameSpace = valueArgs[1];
            alias = classRemoteCall.alias();
        }

        if (classRemoteCall == null && callInfo != null) {
            appCode = callInfo.getAppCode();
            nameSpace = callInfo.getNameSpace();
            alias = callInfo.getAlias();
        }

        if (StringUtils.isEmpty(appCode) || StringUtils.isEmpty(nameSpace)) {
            logger.error("can not get {} from iris,check please", cls);
            return null;
        }

        RPCStubBeanFactory rpChainBeanFactory = new RPCStubBeanFactory(appCode, nameSpace, alias, cls);
        rpChainBeanFactory.afterPropertiesSet();
        T remoteBean = (T) rpChainBeanFactory.getObject();
        return remoteBean;
    }


    public static void handleAuthPermission(Object context, Object schema) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IAuthPermissionService service = isvBeanService.getService(IAuthPermissionService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.authPermissionService = service;
        authPermissionService.handleAuthPermission(null, context, schema);
    }

    /**
     * 切换默认实现组
     *
     * @param defBeanGroup 实现方定义的默认组
     * @param context      上下文
     * @param schema       查询条件
     * @throws Exception
     */
    public static void handleAuthPermission(String defBeanGroup, Object context, Object schema) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IAuthPermissionService service = isvBeanService.getService(IAuthPermissionService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.authPermissionService = service;
        authPermissionService.handleAuthPermission(defBeanGroup, context, schema);
    }

    /**
     * 获取主组织权限，根据用户及服务查询权限范围内的组织，不进行分组，合并返回；
     *
     * @param orgEntryParam 查询条件,用户、租户为友互通的用户合租户
     * @return 用户在服务下所拥有的组织、部门权限
     * @throws Exception
     */
    public static OrgPermVO getUserMasterOrgPermission(OrgEntryParam orgEntryParam) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IServiceIsolateService service = isvBeanService.getService(IServiceIsolateService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.serviceIsolateService = service;
        //后面替换成调用 getUserMasterOrgPermWithOutGroup 方法,考虑效率问题，暂停替换
        return serviceIsolateService.findUserOrgPermission(orgEntryParam);
    }

    /**
     * 获取主组织权限，根据用户及服务查询权限范围内的组织，包含新版组织权限接口能力(是否过滤停用组织\过滤商家组织\过滤企业账号级......)；
     *
     * @return 用户在服务下所拥有的组织、部门权限
     * @throws Exception
     */
    public static Set<String> getUserMasterOrgPermission(OrgPermissionsParam orgPermParam) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IOrgPermissionService service = isvBeanService.getService(IOrgPermissionService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.orgPermissionService = service;
        //后面替换成调用 getUserMasterOrgPermWithOutGroup 方法,考虑效率问题，暂停替换
        return orgPermissionService.getOrgPermissions(orgPermParam);
    }

        public static Set<String> getUserMasterOrgPermission(String yhtUserId, String yhtTenantId, String authId, Boolean includeDisable) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IServiceIsolateService service = isvBeanService.getService(IServiceIsolateService.class, AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.serviceIsolateService = service;
        List<String> mainOrgAuthList = serviceIsolateService.findMainOrgPermission(yhtUserId, authId, yhtTenantId, includeDisable);
        Set mainOrgAuthSet = new HashSet(mainOrgAuthList);
        return mainOrgAuthSet;
    }


    /**
     * 获取主组织权限，根据用户及服务查询权限范围内的组织，按角色进行分组返回。
     *
     * @param orgEntryParam 查询条件,用户、租户为友互通的用户合租户
     * @return 用户在服务下不同角色中所拥有的组织、部门权限
     * @throws Exception
     */
    public static List<OrgPermVO> getUserMasterOrgPermWithOutGroup(OrgEntryParam orgEntryParam) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IServiceIsolateService service = isvBeanService.getService(IServiceIsolateService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.serviceIsolateService = service;
        return serviceIsolateService.findUserOrgPermWithOutGroup(orgEntryParam);
    }

    /**
     * 批量获取数据权限，根据用户查询数据权限范围
     *
     * @param requestDto 查询条件
     * @return 批量单据下的数据权限过滤范围
     * @throws Exception
     */
    public static List<DataPermissionResponseDto> getUserDataPermissions(DataPermissionRequestDto requestDto) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IDataPermissionService service = isvBeanService.getService(IDataPermissionService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.dataPermissionService = service;
        return dataPermissionService.batchGetDataPermission(requestDto);
    }

    /**
     * 获取功能权限，根据用户查询权限范围内的服务和按钮编码
     *
     * @param yhtTenant        友互通租户
     * @param yhtUserId        友互通用户
     * @param permissionFilter 过滤条件
     * @return 服务+按钮 编码
     * @throws Exception
     */
    public static Set<String> getUserServiceAndButtonPerms(String yhtTenant, String yhtUserId, DiworkPermissionFilter permissionFilter) throws Exception {
        /*if(instance == null){return null;}
        return instance.getServiceAndButtonPerms(yhtTenant,yhtUserId,permissionFilter);*/
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IDiWorkPermissionService service = isvBeanService.getService(IDiWorkPermissionService.class, AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.diWorkPermissionService = service;
        return diWorkPermissionService.getServiceAndButtonPerms(yhtTenant, yhtUserId, permissionFilter);
    }

    /**
     * 获取功能权限，根据用户查询角色权限范围内的服务和按钮编码,并按角色汇总返回
     * *** 返回的Map中，可能存有无效的TenantRole数据，表示直接关联用户上的功能权限，未直接或者间接关联角色，需注意判断roleId或roleCode属性非空
     *
     * @param yhtTenant        友互通租户
     * @param yhtUserId        友互通用户
     * @param permissionFilter 过滤条件
     * @return 角色下服务+按钮编码
     * @throws Exception
     */
    public static Map<TenantRole, Set<String>> getUserServiceAndButtonPermsWithOutGroup(String yhtTenant, String yhtUserId, DiworkPermissionFilter permissionFilter) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IDiWorkPermissionService service = isvBeanService.getService(IDiWorkPermissionService.class, AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.diWorkPermissionService = service;
        return diWorkPermissionService.getUserServiceAndButtonPermsWithOutGroup(yhtTenant, yhtUserId, permissionFilter);
    }

    /**
     * 查询租户下角色集合
     *
     * @param yhtTenantId 友互通租户
     * @return 角色集合
     */
    public static List<TenantRole> getTenantRoles(String yhtTenantId) {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        ITenantRoleService service = isvBeanService.getService(ITenantRoleService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.tenantRoleService = service;
        return tenantRoleService.findRolesBySystemCodeAndTenantId(SYSTEM_DIWORK, yhtTenantId);
    }

    /**
     * 查询租户下用户角色授权数据
     *
     * @param yhtTenantId 友互通租户
     * @return 用户角色授权数据
     */
    public static List<TenantRoleUser> getTenantRoleUsers(String yhtTenantId) {
        /*if(tenantRoleUserService == null || StringUtils.isEmpty(yhtTenantId)){return null;}
        List<TenantRoleUser> roleUsers = tenantRoleUserService.findByTenantIdAndSysId(yhtTenantId,SYSTEM_DIWORK);
        if(CollectionUtils.isNotEmpty(roleUsers)){
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String currentDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            List<TenantRoleUser> filterRoleUsers = roleUsers.stream().filter(data->{
                try {
                    return (sdf.parse(currentDate).after(sdf.parse(data.getBegindate())) || sdf.parse(currentDate).equals(data.getBegindate()))
                            && (sdf.parse(currentDate).before(sdf.parse(data.getEnddate())) || sdf.parse(currentDate).equals(data.getEnddate()));
                } catch (ParseException e) {
                    logger.error("根据时间过滤授权有效期失败，返回空结果集");
                    return false;
                }
            }).collect(Collectors.toList());
            return filterRoleUsers;
        }
        return roleUsers;*/
        return null;
    }

    /**
     * 根据角色编码查询关联用户授权数据
     *
     * @param roleCode    角色编码
     * @param yhtTenantId 友互通ID
     * @return 用户角色授权数据
     */
    public static List<TenantRoleUser> getTenantRoleUsersByRole(String roleCode, String yhtTenantId) {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        ITenantRoleService service = isvBeanService.getService(ITenantRoleService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.tenantRoleService = service;
        TenantRole tenantRole = null;
        try {
            tenantRole = tenantRoleService.getRoleByRoleCode(SYSTEM_DIWORK, yhtTenantId, roleCode);
            if (null == tenantRole) {
                logger.error("根据角色编码（" + roleCode + "）查询不到角色");
                return new ArrayList<TenantRoleUser>();
            }
        } catch (Exception e) {
            logger.error("根据角色编码（" + roleCode + "）查询不到角色");
            return null;
        }
        List<TenantRoleUser> tenantRoleList = getTenantRoleUsers(yhtTenantId);
        if (CollectionUtils.isNotEmpty(tenantRoleList)) {
            TenantRole finalTenantRole = tenantRole;
            return tenantRoleList.stream().filter(data -> data.getRoleId().equals(finalTenantRole.getRoleId())).collect(Collectors.toList());
        }
        return null;

    }


    /**
     * 批量保存角色
     *
     * @param roleList 角色集合
     * @return 保存后角色
     */
    public static List<TenantRole> saveTenantRoles(List<TenantRole> roleList) {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        ITenantRoleService service = isvBeanService.getService(ITenantRoleService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.tenantRoleService = service;
        return tenantRoleService.save(roleList);
    }

    /**
     * 批量保存角色用户授权关系
     *
     * @param roleUserList 用户角色关联关系集合
     * @return 保存后用户角色关联关系
     */
    public static List<TenantRoleUser> saveTenantRoleUsers(List<TenantRoleUser> roleUserList) {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        ITenantRoleUserService service = isvBeanService.getService(ITenantRoleUserService.class, Constants.AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.tenantRoleUserService = service;
        return tenantRoleUserService.saveRoles(roleUserList);
    }

    public static String isUserHasOrgPermission(String yhtToken, String orgId, String authId) throws Exception {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IOrgPermManagerService service = isvBeanService.getService(IOrgPermManagerService.class, ORGDOMAIN, null, null);
        AuthSdkFacadeUtils.orgPermManagerService = service;
        return orgPermManagerService == null ? null : orgPermManagerService.isUserHasOrgPermission(yhtToken, orgId, authId);
    }

    public static void handleAuthPermissionForRef(Object billContext, Object billData) throws Exception {
        if (roleConstraintResolver != null) {
            roleConstraintResolver.handleRoleConstraintForRef(billContext, billData);
        }
    }

    public static boolean checkFunAuthorityByAuthId(String yhtTenantId, String yhtUserId, String authId) {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        IDiWorkPermissionService service = isvBeanService.getService(IDiWorkPermissionService.class, AUTHDOMAIN, null, null);
        AuthSdkFacadeUtils.diWorkPermissionService = service;
        return diWorkPermissionService == null ? false : diWorkPermissionService.checkFunAuthorityByAuthId(yhtTenantId, yhtUserId, authId);
    }

    public static boolean checkFunAuthorityByAuthId(String yhtTenantId, String yhtUserId, String authId, String bnum, String dynamicAuthToken) {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        if(sdkDynamicTokenManagerService != null && StringUtils.isNotEmpty(dynamicAuthToken)){
            return AuthSdkFacadeUtils.sdkDynamicTokenManagerService.validateTokenNotUseAuth(bnum, dynamicAuthToken);
        }
        return checkFunAuthorityByAuthId(yhtTenantId, yhtUserId, authId);
    }

        public static Set<String> checkAuthIds(String yhtTenantId, String yhtUserId, Set<String> authIds, String bnum, String dynamicAuthToken) {
        if (null != sdkDynamicTokenManagerService && StringUtils.isNotEmpty(dynamicAuthToken)) {
            boolean isAuth = sdkDynamicTokenManagerService.validateTokenNotUseAuth(bnum, dynamicAuthToken);
            return (Set)(isAuth ? authIds : new HashSet());
        } else {
            ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
            IDiWorkPermissionService service = isvBeanService.getService(IDiWorkPermissionService.class, AUTHDOMAIN, null, null);
            AuthSdkFacadeUtils.diWorkPermissionService = service;
            return diWorkPermissionService.checkAuthIds(yhtTenantId, yhtUserId, authIds);
        }
    }
}
